﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.Kinect;

namespace KinectMenagerNamespace
{
    public class GestureEventArgs: EventArgs
    {
        private DateTime startTime, endTime;
        private DateTime[] times;

        public DateTime[] Times
        {
            get { return times; }
            set { times = value; }
        }
        public DateTime StartTime
        {
            get
            {
                return startTime;
            }
        }
        public DateTime EndTime
        {
            get
            {
                return endTime;
            }
        }
        public TimeSpan Duration
        {
            get
            {
                return (EndTime - StartTime);
            }
        }
        private GestureState state;

        public GestureState State
        {
            get { return state; }
        }

        public GestureEventArgs(DateTime start, DateTime end, GestureState state, DateTime[] times)
        {
            this.startTime = start;
            this.endTime = end;
            this.state = state;
            this.times = times;
        }
    }

    public enum GestureState
    {
        InProgress, Fail, Succes
    }

    public delegate void GestureHandler(GestureEventArgs args);

    public class KinectGesture
    {
        private KinectGesturePart[] parts;
        private DateTime startTime;
        private DateTime endTime;
        private DateTime[] times;
        private GestureState state = GestureState.InProgress;

        private TimeSpan maxDuration;
        private int currentGesturePart = 0;
        private bool enable = false; 

        public event GestureHandler OnGestureStart = null;
        public event GestureHandler OnGestureEnd = null;

        public event GestureHandler OnGestureFail = null;
        public event GestureHandler OnGestureSucces = null;

        public KinectGesture(KinectGesturePart[] parts, TimeSpan maxDuration)
        {
            this.maxDuration = maxDuration;
            this.parts = parts;
            this.times = new DateTime[parts.Length];
        }

        public void Update(Skeleton skeleton)
        {
            if (enable)
            {
                if (currentGesturePart == 0)
                {
                    if (parts[currentGesturePart].Update(skeleton) == GestureState.Succes)
                    {
                        startTime = DateTime.Now;
                        times[currentGesturePart] = startTime;
                        state = GestureState.InProgress;
                        if (OnGestureStart != null)
                        {
                            OnGestureStart.Invoke(new GestureEventArgs(startTime, endTime, state, times));
                        }

                        if (currentGesturePart == parts.Length - 1)
                        {
                            endTime = DateTime.Now;
                            times[currentGesturePart] = endTime;
                            state = GestureState.Succes;
                            if (OnGestureSucces != null)
                            {
                                OnGestureSucces.Invoke(new GestureEventArgs(startTime, endTime, state, times));
                            }
                            if (OnGestureEnd != null)
                            {
                                OnGestureEnd.Invoke(new GestureEventArgs(startTime, endTime, state, times));
                            }
                            currentGesturePart = 0;
                            return;
                        }

                        currentGesturePart++;
                    }

                    return;
                }

                if ((DateTime.Now - startTime) < maxDuration)
                {
                    GestureState partState = parts[currentGesturePart].Update(skeleton);
                    if (partState == GestureState.Succes)
                    {
                        if (currentGesturePart == parts.Length - 1)
                        {
                            endTime = DateTime.Now;
                            times[currentGesturePart] = endTime;
                            state = GestureState.Succes;
                            if (OnGestureSucces != null)
                            {
                                OnGestureSucces.Invoke(new GestureEventArgs(startTime, endTime, state, times));
                            }
                            if (OnGestureEnd != null)
                            {
                                OnGestureEnd.Invoke(new GestureEventArgs(startTime, endTime, state, times));
                            }
                            currentGesturePart = 0;
                            return;
                        }
                        else
                        {
                            times[currentGesturePart] = DateTime.Now;
                            currentGesturePart++;
                            return;
                        }
                    }
                    else if (partState == GestureState.Fail)
                    {
                        endTime = DateTime.Now;
                        times[currentGesturePart] = endTime;
                        state = GestureState.Fail;
                        if (OnGestureFail != null)
                        {
                            OnGestureFail.Invoke(new GestureEventArgs(startTime, endTime, state, times));
                        }
                        if (OnGestureEnd != null)
                        {
                            OnGestureEnd.Invoke(new GestureEventArgs(startTime, endTime, state, times));
                        }
                        currentGesturePart = 0;
                        return;
                    }
                }
                else
                {
                    endTime = DateTime.Now;
                    times[currentGesturePart] = endTime;
                    state = GestureState.Fail;
                    if (OnGestureFail != null)
                    {
                        OnGestureFail.Invoke(new GestureEventArgs(startTime, endTime, state, times));
                    }
                    if (OnGestureEnd != null)
                    {
                        OnGestureEnd.Invoke(new GestureEventArgs(startTime, endTime, state, times));
                    }
                    currentGesturePart = 0;
                    return;
                }
            }
        }

        public void Enable()
        {
            enable = true;
        }

        public void Disable()
        {
            enable = false;
            currentGesturePart = 0;
        }

        public void Restart()
        {
            enable = true;
            currentGesturePart = 0;
        }
    }
}
